Skip to content

Release 4.3.0 - #265

Merged
admin-sbneto merged 15 commits into
masterfrom
develop
Aug 4, 2026
Merged

Release 4.3.0#265
admin-sbneto merged 15 commits into
masterfrom
develop

Conversation

@sbneto

@sbneto sbneto commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

TL;DR — changelog for 4.3.0

  • Known-goodness is keyed on the instance state the server reports, not on the presence of a feed list.
  • A known-good sample that was scanned before it was flagged is no longer described as unscanned.
  • Known-good result lines colour by their verdict instead of unconditionally by their status.
  • --no-color is honoured end to end, including the log prefixes.
  • The SDK dependency floor is raised to polyswarm-api 4.3.0.

Requires

  • polyswarm-cli #264 merged into develop first (the 4.3.0 bump + SDK floor).
  • polyswarm-api's Release 4.3.0 merged to master first, so the floored dependency resolves from PyPI.

sbneto and others added 14 commits July 28, 2026 17:13
`is_known_good` was `state == 'KNOWN_GOOD' or bool(known_good_sources)`, and the
Detections line it drives replaces the engine verdicts with "this artifact is a
known-good binary … it is not scanned".

That was harmless only because the server emitted the feed list exclusively for
instances already in the known-good state. It no longer does: the list is now
present whenever the sha256 matches a known-good record, including on a fully
scanned instance with real detections and a PolyScore, so the fallback would have
reported such a sample as never scanned.

The state is the single reliable signal for "known-good, bytes withheld", so it
alone decides; the feed list only shapes the message. Keeps the defensive getattr
for older SDKs — one consequence, now documented: an SDK without `.state` renders
a known-good instance as an ordinary one rather than mislabelling a scanned one.
…tate

The change made `.state` load-bearing with no fallback, but the dependency floor
still allowed 4.0.0, which predates it — so a user on an in-range SDK would get a
known-good instance rendered as an ordinary window-closed one ("No engines
responded… trigger a rescan"), silently. `.state` shipped in 4.1.0, and the SDK
contract says the floor must exclude releases missing behaviour the CLI relies on.

Also: specs/04-testing.md's invariant said tests drive the CLI through CliRunner
and never call internal functions, which as written forbade the formatter-unit
tests this change adds — the spec now sanctions that style and says when it is the
right choice. specs/03-formatters.md no longer overstates the feed-list guard as
load-bearing. And two branches where the flag has to lose or be ignored are now
pinned: a failed known-good instance reports the failure, and an instance with
feeds but no state renders as an ordinary one — the assertion that would catch the
removed fallback being reintroduced.
…ample is unscanned

Two behaviours the CLI relies on arrived in 4.2.0, not 4.1.0: llm_report_create
only started sending the client's community then (and `report llm-create` does not
pass one itself, so on 4.1.0 a private-community report is created without it), and
streaming downloads only started raising NoResultsException on a 204 then, which
the download command's no-results exit code depends on.

The assertion loop was not gated by the known-good flag, so an instance carrying
that state *and* assertions rendered "it is not scanned" immediately followed by
per-engine verdicts. That pairing is no longer hypothetical: the server now
reconciles a previously scanned instance into the known-good state while
deliberately preserving its assertions, polyscore and detections, so it is exactly
what a client receives. The rendering now says both things without contradicting
itself — the bytes are withheld, and here are the results we already had.
Review follow-ups on the known-good rendering:

- A known-good instance carrying malicious detections rendered the whole
  Detections line green, including the "N/M engines reported malicious"
  clause the ordinary branch renders red. Green on 40/50 is a weaker
  warning than the same instance gave before it was reconciled, which is
  the class of mis-signal this rendering exists to fix. Red when there
  are malicious assertions and the window is closed; green otherwise.
- The counts are now guarded on window_closed like every other branch, so
  an open window's numbers are never presented as final.
- Pin the colour decision against TextOutput(color=True): every existing
  test unstyles its output, so the green/red choice was unobservable.
- Drop the `del instance.state` half of the no-state test — it mutates an
  SDK resource's internals, which specs/05 forbids, and pins a
  configuration specs/03 declares unsupported. The server-omits-state
  case it shared covers the real behaviour.
- Document the floor's two preconditions (published on PyPI, and declared
  by the SDK's develop archive) — both verified for 4.2.0.
…t goes red

specs/03 states it as a rule; _detections_line() filters the styled render down
to the Detections line, so nothing observed it.
Review follow-ups.

`self.color` was assigned twice in __init__ and read nowhere: every
_white/_red/_green helper called click.style() unconditionally, so
`--no-color` was a no-op for text output while JSONOutput honoured it and
specs/03 claimed TextOutput did too. Masked in practice because click strips
ANSI when stdout is not a tty. All five helpers now go through one `_paint`,
which is the only place the flag is read.

That also corrects what this PR's own colour tests pin: it is the absent
click.unstyle, not the `color=` argument, that made the green/red decision
observable. The spec and the helper docstring said otherwise.

Also:
- The spec header said "majority-malicious" while the code reddens on any
  malicious assertion — the same threshold the ordinary branch uses.
- Pin the open-window colour. That is the one combination where the
  `and window_closed` conjunct is load-bearing: the instance has a malicious
  assertion, so dropping it turns the line red while it reads "its scan has
  not finished running yet", and every existing test still passed.
…inned

`state` is load-bearing with no fallback, and a Style-3 formatter test cannot
see the transport boundary. Rather than leave that inferred: the key and the
label were read off the server's ArtifactInstanceSerializer
(`'state': instance.state.name`, and BountyState.KNOWN_GOOD.name is exactly
'KNOWN_GOOD'), and the thing that would catch a future rename is the server's
own suite — this repo replays frozen cassettes with no VCR-off e2e job, so a
recorded body would keep replaying the old shape.

Same treatment for the open-window branch: the claim that reconciliation
cannot produce one is now stated against the mechanism it rests on
(RECONCILABLE_STATES, and SETTLED requiring window_closed), with the fix to
apply if that ever stops holding.
…o end

Review follow-ups.

- The previous commit made TextOutput read self.color, but setup_logging never
  received the flag, so `polyswarm --no-color -v …` still emitted a green log
  prefix on a tty — the same half-honoured flag, one layer over. Threaded
  through, and the spec now states the flag's scope.
- TestColorFlag pinned _paint, not the option: the flag travels through
  `formatters[output_format](color=color, …)` in the command group, which a
  formatter unit test cannot observe (specs/04 says so itself). Added a
  CliRunner test with color=True, which stops click stripping ANSI off the
  non-tty capture so the two runs differ only in the flag.
- specs/03 claimed _paint means "a new helper cannot style unconditionally".
  It is a convention, not an enforcement point — reworded.
- specs/05: the floor precondition needs the version read off the archive's own
  tree, because PEP 440 orders 4.2.0.dev1 < 4.2.0 and the SDK has a bumpversion
  dev part. Both files on origin/develop say 4.2.0 with no suffix.
- Anchor the PolyScore assertion on the parsed line: 'PolyScore: 0.9' also
  matches 0.95, and the :.20f render is not the literal '0.9'.
Review follow-ups.

- The colour test ran at default verbosity, so the level was WARNING and no
  record ever reached NamedColorFormatter: the log-prefix half of the fix was
  untested. Added the -v pair.
- Both colour tests now mock `Polyswarm.search_hashes` (specs/04 Style 2)
  instead of replaying a cassette. The response content is irrelevant to
  whether the flag reaches the renderer, so a cassette would have to be
  recorded against a live stack for a test that never exercises the server —
  and borrowing another test's cassette coupled the two through the re-record
  path, since unittest orders methods alphabetically and this one sorts first.
- `_render_styled`'s docstring said `color=True` was "passed only for
  emphasis". That was true before `_paint`; it is now load-bearing, and saying
  otherwise invites a future editor to drop it and silently disarm every colour
  assertion. Corrected in the docstring and in specs/03.
Review follow-ups.

- _run_color_pair patched Polyswarm.search_hashes, which is CLI code, so it cut
  utils.parallel_executor_iterable_results out of the run — and the docstring
  cited it as "specs/04 Style 2", which defines that style as patching
  polyswarm_api.api.PolyswarmAPI.<method>. Now patches PolyswarmAPI.search: same
  assertions, correct seam, and the citation is true.
- specs/03 and _paint's docstring both credited JSONOutput with honouring
  --no-color. It has no __init__ and emits plain JSON; PrettyJSONOutput is the
  one that reads the flag. The contrast is the stated rationale for _paint, so
  naming the wrong class undercut it.
Review follow-up. The text keyed on `valid_assertions and window_closed`; the
colour keyed on `malicious_assertions and window_closed`. Two differently-shaped
conditions that had to agree, held together only by the SDK guaranteeing
malicious_assertions is a subset of valid_assertions (both filter on `mask`, one
additionally on `verdict`). It is a subset today — verified — so there is no live
defect, but a rendering rule in this repo should not depend on a property of
another repo's resource class to stay coherent.

Each branch now names its own paint function, so the count branch is the only one
that can redden and the clause it renders is the one being coloured.
fix: key known-goodness on the instance state, not on the feed list
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review — Release 4.3.0

The code changes themselves look correct and well covered. Everything below is about the release mechanics and spec bookkeeping this PR carries onto master.

1. This PR as it stands is not a release — no version bump

The merge diff has pyproject.toml version = "4.2.1" and src/polyswarm/__init__.py __version__ = '4.2.1' — identical to master. AGENTS.md:

PyPI release happens automatically when pyproject.toml's version changes on master.

Merging as-is publishes nothing while the PR is titled Release 4.3.0. The Requires section is right that #264 must land on develop first; flagging it because the diff currently shown for review is the pre-#264 one, so this diff needs re-reading after #264 merges — the two files that decide the release aren't in it.

Same for the TL;DR bullet "The SDK dependency floor is raised to polyswarm-api 4.3.0": the diff under review raises it to >=4.2.0, not 4.3.0. That is #264's change, not this one.

2. Spec drift the moment #264 lands — specs/05 and specs/03 will state the wrong floor

This PR adds to specs/05-sdk-contract.md a section headed Current floor — polyswarm_api>=4.2.0, with a specific two-item justification (llm_report_create passing community, and streaming 204 -> NoResultsException). It also adds to specs/03-formatters.md:

Both attributes ship in SDK 4.1.0, but the dependency floor is polyswarm_api>=4.2.0 — set by two other behaviours the CLI depends on

#264 moves the floor to >=4.3.0 and touches neither spec. So the release that reaches master ships pyproject.toml saying >=4.3.0 alongside two spec sections saying >=4.2.0, including a heading. That is exactly what AGENTS.md forbids:

Update the spec in the same PR as the code change; if a PR drifts from a spec, the spec is wrong until proven otherwise.

Worse, the reasons conflict: #264's body attributes the floor to "the typed known-good refusal and probe fixes this CLI renders", while specs/03 (added here) asserts the known-good rendering attributes ship in 4.1.0 and are explicitly "not what sets the floor". One of those is wrong. Fix: #264 should rewrite the specs/05 floor section (new heading, new justification for what 4.3.0 specifically adds) and the specs/03 sentence — or do it here before merge.

3. Verify the floor's own preconditions before this reaches master

specs/05, added in this PR, sets the gate that #264's floor has to clear:

a floor bump has two preconditions: the version is on PyPI, and the SDK's develop declares at least that version

a floor above the newest published version breaks pip install polyswarm-cli for every consumer the moment it reaches master

With >=4.3.0 that means polyswarm-api 4.3.0 must be on PyPI before this merges — and per the PEP 440 note in the same section, the SDK branch's declared version must be read off its own tree with no .devN suffix (4.3.0.dev1 < 4.3.0, so the archive build gets silently replaced from PyPI and CI stops testing the SDK branch at all). The Requires ordering covers this; it just needs to be confirmed at merge time, because inverting it is a hard break for every installer, not a CI failure.

4. Minor — internal ticket ID in the promoted history

Merge pull request #262 from polyswarm/dn-8425-known-good-status-signal carries dn-8425 into a commit message this PR promotes to master. AGENTS.md: "Don't reference ticket IDs or internal project codes in commit messages, PR titles, or PR descriptions." Not worth rewriting history for; worth avoiding the branch-name leak on future merges.


Verified clean

  • formatters/text.pyis_known_good keyed solely on state == 'KNOWN_GOOD' with known_good_sources demoted to message-shaping matches specs/03 as rewritten; the clause/colour single-branch refactor does remove the malicious_assertionsvalid_assertions cross-repo dependency as claimed; not instance.failed gating plus Status: Failed ordering first is consistent with the spec's failure-outranks rule.
  • _paint is now the only reader of self.color, and all five helpers route through it. Grepped src/ for click.style / click.secho / colorama: the only remaining sites are formatters/json.py (PrettyJSONOutput, already gated on self.color) and the log prefix fixed here — so the "end to end" claim in the specs/03 scope-of---no-color paragraph holds.
  • Log-prefix fix: the color closure is captured per setup_logging call, the pre-existing core.ColorFormatter.colors['info'] = dict(fg='green') mutation is what makes \x1b[32minfo [polyswarm the right assertion, and -v is genuinely required (default verbosity is WARNING, so no record reaches NamedColorFormatter) — the test comments are accurate.
  • Cassette expectations are unaffected: .click files were recorded through CliRunner(color=False), which strips ANSI, and the new code strictly emits fewer escapes.
  • _run_color_pair mocks PolyswarmAPI.search, which is the correct seam — patching Polyswarm.search_hashes would cut utils.parallel_executor_iterable_results out of the run, as its docstring says.
  • The new specs/04 Style 3 obligation ("a command whose rendering is covered by Style 3 still needs at least one CliRunner test proving the command reaches the formatter at all") is satisfied by the existing test_search_hash_with_text_output plus the two new colour tests.
  • Branch base is correct for a develop -> master release PR.

mjbradford89
mjbradford89 previously approved these changes Aug 4, 2026
release: bump version to 4.3.0, floor the SDK at 4.3.0
@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review — release 4.3.0

Gitflow is correct: develop → master, version bumped in pyproject.toml + src/polyswarm/__init__.py + [tool.bumpversion], which is exactly where AGENTS.md puts a version bump. The known-good rendering change and the --no-color fix look right — _paint is now the only reader of self.color (grepping for click.style under src/polyswarm/ shows no bypasses left), the clause and its colour are decided in one if/elif so the two cannot drift, and the new TestColorFlag plus test_color_flag_reaches_the_text_formatter / test_color_flag_reaches_the_log_prefix cover both halves of the flag at the right seams (PolyswarmAPI.search, per specs/04 Style 2). No correctness issues found in the diff.

Three things to fix before this merges.

1. The SDK floor bump is spec drift — pyproject.toml says 4.3.0, three spec passages still say 4.2.0

pyproject.toml:25 now floors polyswarm_api>=4.3.0, but the docs this PR also ships describe a 4.2.0 floor:

  • specs/05-sdk-contract.md:77 — the heading Current floor — polyswarm_api>=4.2.0, and the two justifying behaviours at :79-82 (llm_report_create community, streaming 204 -> NoResultsException) are both 4.2.0 facts.
  • specs/05-sdk-contract.md:75 — records the mandated archive check as "For the current floor both were read from origin/develop: version = 4.2.0 and version = 4.2.0, no suffix."
  • specs/03-formatters.md:145"the dependency floor is polyswarm_api>=4.2.0 — set by two other behaviours…"

AGENTS.md: "Update the spec in the same PR as the code change; if a PR drifts from a spec, the spec is wrong until proven otherwise." Here the code and the spec disagree inside a single PR. The fix: floor the SDK pin at 4.3.0 (typed known-good refusal + probe fixes) commit also has an empty body, so the only record of why the floor moved is a parenthetical in a headline — and specs/05 §Version pin requires the floor be "the lowest SDK version exposing everything the CLI uses", which means the 4.3.0-only behaviours need naming the way 4.2.0 two were. Please retitle that section to 4.3.0, list the 4.3.0-only behaviours the CLI relies on, and fix the 03-formatters.md:145 cross-reference.

2. The floor preconditions were verified for 4.2.0, not for 4.3.0

specs/05-sdk-contract.md:73: "a floor bump has two preconditions: the version is on PyPI, and the SDK develop declares at least that version." Neither is recorded for 4.3.0, and both bite here:

  • .gitlab-ci.yml:28-29 does pip install $ARCHIVE/$CI_COMMIT_BRANCH.zip || … develop.zip and then pip install .[tests]. This PR head is develop, so CI installs the SDK develop archive. If that archive declares anything below 4.3.0 — including a 4.3.0.devN suffix, which PEP 440 orders below 4.3.0 and which the SDK [tool.bumpversion.parts.dev] can produce (spec:75 calls this out by name) — the second install silently replaces the archive build from PyPI and CI stops testing the SDK branch at all, with no error.
  • A floor above the newest published SDK breaks pip install polyswarm for every consumer the moment this lands on master.

The PR body Requires section says polyswarm-api 4.3.0 must reach master first, which covers the PyPI half as a merge-order gate — but please confirm the declared version on the SDK origin/develop tree too, and record both readings in specs/05 the way the 4.2.0 bump did.

3. Internal ticket ID in a commit that will land on master

Merge pull request #262 from polyswarm/dn-8425-known-good-status-signal carries dn-8425 in the commit message. AGENTS.md: "Do not reference ticket IDs or internal project codes in commit messages, PR titles, or PR descriptions. This repo is public." It is already on develop, so it needs a squash/reword on the way to master rather than a follow-up commit.

Minor

The Requires section links polyswarm-cli #264 — a PR on this repo. specs/05 §Coordinated changes defines that section as the link to the SDK PR. The polyswarm-api 4.3.0 release is only mentioned in prose; a direct link would make the gate checkable.

@sbneto
sbneto requested a review from mjbradford89 August 4, 2026 19:17
@admin-sbneto
admin-sbneto merged commit 739d156 into master Aug 4, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants